﻿#region Disclaimer/Info
///////////////////////////////////////////////////////////////////////////////////////////////////
// MetaCollection
// 
// MetaCollection is a system to provide a standard structure, permissions and metadata service
// for content organization.
//
// This project is hosted at Google Code at http://code.google.com/p/metacollection/
//
// This project is licensed under the BSD license.  See the License.txt file for more information.
///////////////////////////////////////////////////////////////////////////////////////////////////
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MetaCollection.Framework
{
	/// <summary>
	/// Types of Requests that a Provider may support
	/// </summary>
	/// <remarks>The IsValid extension method can determine if a given RequestTypes flag set is
	/// valid or not.</remarks>
	[Flags]
	public enum RequestTypes
	{
		None = 0,
		/// <summary>
		/// Gets the specified item
		/// </summary>
		/// <remarks>Can be used with the optional flags ProcessDirectDescendents, ProcessAllDescendents</remarks>
		GetItem = 1,
		/// <summary>
		/// Gets the Resource stream for an item.
		/// </summary>
		GetResource = 1 << 1,
		/// <summary>
		/// A request to update or set properties, permissions on an item
		/// </summary>
		/// <remarks>Can be used with the optional flags ProcessDirectDescendents, ProcessAllDescendents</remarks>
		SetItem = 1 << 2,
		/// <summary>
		/// A request to replace the resource stream on an item
		/// </summary>
		SetResource = 1 << 3,
		/// <summary>
		/// A request to delete an item (and it's resource)
		/// </summary>
		/// <remarks>Can be used with the optional flags ProcessDirectDescendents, ProcessAllDescendents</remarks>
		DeleteItem = 1 << 4,
		/// <summary>
		/// Returns the Validation information for the given item (type).
		/// </summary>
		GetItemSpecification = 1 << 5,
		/// <summary>
		/// A request with Form Post data to be applied to an item.
		/// </summary>
		PostToItem = 1 << 6,


		/// <summary>
		/// Indicates that the request should only be applied to the item specified in the request.
		/// </summary>
		/// <remarks>For Requests that do not specify another processing instruction this is the default.</remarks>
		ProcessSingleItem = 1 << 7,
		/// <summary>
		/// Indicates that the request should only be applied to the direct children of the item in the request.
		/// </summary>
		/// <remarks> This includes the item as well as the item and its children</remarks>
		ProcessDirectDescendents = 1 << 8,
		/// <summary>
		/// Indicates that all children (direct and inherited) should be in the scope of the request.
		/// </summary>
		/// <remarks> This includes the item as well as the item and its children</remarks>
		ProcessAllDescendents = 1 << 9,

		/// <summary>
		/// Indicates that this request is targeting a specific version.  This version to use must be specified or the request can not be processed.
		/// </summary>
		VersionSpecific = 1 << 10,
		/// <summary>
		/// Indicates that this request applies to the published version of an item only.
		/// </summary>
		VersionPublished = 1 << 11,
		/// <summary>
		/// Indicates that the latest version of an item should be used for this request.
		/// </summary>
		VersionLatest = 1 << 12,
		/// <summary>
		/// Indicates that all versions of an item are included in this type of request.
		/// </summary>
		VersionAll = 1 << 13
	}

	public static class RequestTypeExtensions
	{
		/// <summary>
		/// An array of all possible valid flag combinations for a RequestTypes instance
		/// </summary>
		private static readonly RequestTypes[] VALIDFLAGS = new[] { 
			RequestTypes.DeleteItem,
			RequestTypes.GetItem,		
			RequestTypes.GetItemSpecification,
			RequestTypes.GetResource,
			RequestTypes.SetItem,
			RequestTypes.SetResource,
			RequestTypes.PostToItem,

			RequestTypes.DeleteItem | RequestTypes.ProcessSingleItem,
			RequestTypes.GetItem | RequestTypes.ProcessSingleItem,			
			RequestTypes.GetItemSpecification | RequestTypes.ProcessSingleItem,
			RequestTypes.GetResource | RequestTypes.ProcessSingleItem,
			RequestTypes.SetItem | RequestTypes.ProcessSingleItem,
			RequestTypes.SetResource | RequestTypes.ProcessSingleItem,
			RequestTypes.PostToItem | RequestTypes.ProcessSingleItem,

			RequestTypes.GetItem | RequestTypes.ProcessDirectDescendents,			
			RequestTypes.SetItem | RequestTypes.ProcessDirectDescendents,
			RequestTypes.DeleteItem | RequestTypes.ProcessDirectDescendents,

			RequestTypes.GetItem | RequestTypes.ProcessAllDescendents,			
			RequestTypes.SetItem | RequestTypes.ProcessAllDescendents,
			RequestTypes.DeleteItem | RequestTypes.ProcessAllDescendents,

			/* version specific request types */
			RequestTypes.DeleteItem | RequestTypes.VersionAll,
			RequestTypes.DeleteItem | RequestTypes.VersionSpecific,
			RequestTypes.GetItem | RequestTypes.VersionAll,
			RequestTypes.GetItem | RequestTypes.VersionLatest,
			RequestTypes.GetItem | RequestTypes.VersionPublished,
			RequestTypes.GetItem | RequestTypes.VersionSpecific,			
			RequestTypes.GetItemSpecification | RequestTypes.VersionLatest,
			RequestTypes.GetItemSpecification | RequestTypes.VersionPublished,
			RequestTypes.GetItemSpecification | RequestTypes.VersionSpecific,
			RequestTypes.GetResource | RequestTypes.VersionLatest,
			RequestTypes.GetResource | RequestTypes.VersionPublished,
			RequestTypes.GetResource | RequestTypes.VersionSpecific,
			RequestTypes.SetItem | RequestTypes.VersionLatest,
			RequestTypes.SetItem | RequestTypes.VersionSpecific,
			RequestTypes.SetResource | RequestTypes.VersionLatest,
			RequestTypes.SetResource | RequestTypes.VersionSpecific,
			RequestTypes.PostToItem | RequestTypes.VersionLatest,
			RequestTypes.PostToItem | RequestTypes.VersionSpecific,
			RequestTypes.PostToItem | RequestTypes.VersionPublished,

			RequestTypes.DeleteItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionAll,
			RequestTypes.DeleteItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionSpecific,
			RequestTypes.GetItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionAll,
			RequestTypes.GetItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionLatest,
			RequestTypes.GetItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionPublished,
			RequestTypes.GetItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionSpecific,		
			RequestTypes.GetItemSpecification | RequestTypes.ProcessSingleItem | RequestTypes.VersionLatest,
			RequestTypes.GetItemSpecification | RequestTypes.ProcessSingleItem | RequestTypes.VersionPublished,
			RequestTypes.GetItemSpecification | RequestTypes.ProcessSingleItem | RequestTypes.VersionSpecific,
			RequestTypes.GetResource | RequestTypes.ProcessSingleItem | RequestTypes.VersionLatest,
			RequestTypes.GetResource | RequestTypes.ProcessSingleItem | RequestTypes.VersionPublished,
			RequestTypes.GetResource | RequestTypes.ProcessSingleItem | RequestTypes.VersionSpecific,
			RequestTypes.SetItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionLatest,
			RequestTypes.SetItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionSpecific,
			RequestTypes.SetResource | RequestTypes.ProcessSingleItem | RequestTypes.VersionLatest,
			RequestTypes.SetResource | RequestTypes.ProcessSingleItem | RequestTypes.VersionSpecific,
			RequestTypes.PostToItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionLatest,
			RequestTypes.PostToItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionSpecific,
			RequestTypes.PostToItem | RequestTypes.ProcessSingleItem | RequestTypes.VersionPublished,

			RequestTypes.GetItem | RequestTypes.ProcessDirectDescendents | RequestTypes.VersionLatest,
			RequestTypes.GetItem | RequestTypes.ProcessDirectDescendents | RequestTypes.VersionPublished,
		
			RequestTypes.GetItem | RequestTypes.ProcessAllDescendents | RequestTypes.VersionLatest,
			RequestTypes.GetItem | RequestTypes.ProcessAllDescendents | RequestTypes.VersionPublished,			
		};

		/// <summary>
		/// Determines whether the specified RequestType flagset is valid.
		/// </summary>
		/// <param name="requestType">An instance of RequestType flags to validate.</param>
		/// <returns>
		/// 	<c>true</c> if the specified RequestType flags are valid; otherwise, <c>false</c>.
		/// </returns>
		public static bool IsValid(this RequestTypes requestType)
		{
			return (Array.IndexOf<RequestTypes>(VALIDFLAGS, requestType) >= 0);
		}
		/// <summary>
		/// Gets an enumerator for a instance of <see cref="RequestEventTypes"/>
		/// </summary>
		/// <param name="requestEvent">The request event type instance.</param>
		/// <returns>an ienumberable of RequestEventTypes</returns>
		public static IEnumerable<RequestTypes> GetEnumerator(this RequestTypes requestType)
		{
			if (requestType == RequestTypes.None)
				yield break;
			if ((requestType & RequestTypes.DeleteItem) == RequestTypes.DeleteItem)
				yield return RequestTypes.DeleteItem;
			if ((requestType & RequestTypes.GetItem) == RequestTypes.GetItem)
				yield return RequestTypes.GetItem;					
			if ((requestType & RequestTypes.GetItemSpecification) == RequestTypes.GetItemSpecification)
				yield return RequestTypes.GetItemSpecification; 
			if ((requestType & RequestTypes.GetResource) == RequestTypes.GetResource)
				yield return RequestTypes.GetResource; 
			if ((requestType & RequestTypes.SetItem) == RequestTypes.SetItem)
				yield return RequestTypes.SetItem; 
			if ((requestType & RequestTypes.SetResource) == RequestTypes.SetResource)
				yield return RequestTypes.SetResource;
			if ((requestType & RequestTypes.PostToItem) == RequestTypes.PostToItem)
				yield return RequestTypes.PostToItem;

			if ((requestType & RequestTypes.ProcessSingleItem) == RequestTypes.ProcessSingleItem)
				yield return RequestTypes.ProcessSingleItem;
			if ((requestType & RequestTypes.ProcessDirectDescendents) == RequestTypes.ProcessDirectDescendents)
				yield return RequestTypes.ProcessDirectDescendents;
			if ((requestType & RequestTypes.ProcessAllDescendents) == RequestTypes.ProcessAllDescendents)
				yield return RequestTypes.ProcessAllDescendents;
			
			if ((requestType & RequestTypes.VersionAll) == RequestTypes.VersionAll)
				yield return RequestTypes.VersionAll;
			if ((requestType & RequestTypes.VersionLatest) == RequestTypes.VersionLatest)
				yield return RequestTypes.VersionLatest;
			if ((requestType & RequestTypes.VersionPublished) == RequestTypes.VersionPublished)
				yield return RequestTypes.VersionPublished;
			if ((requestType & RequestTypes.VersionSpecific) == RequestTypes.VersionSpecific)
				yield return RequestTypes.VersionSpecific; 
			yield break;
		}
		/// <summary>
		/// Determines whether the specified request type has type.
		/// </summary>
		/// <param name="requestType">Type of the request.</param>
		/// <param name="typeToMatch">The type to match.</param>
		/// <returns>
		/// 	<c>true</c> if the specified request type has type; otherwise, <c>false</c>.
		/// </returns>
		public static bool HasType(this RequestTypes requestType, RequestTypes typeToMatch)
		{
			return (requestType & typeToMatch) == typeToMatch;
		}

		/// <summary>
		/// Determines whether the specified request type is one of the types in typeSet
		/// </summary>
		/// <param name="requestType">Type of the request.</param>
		/// <param name="typeSet">The set of Types to Check.</param>
		/// <returns>
		/// 	<c>true</c> if [the specified request type] is one of the types in [typeSet]; otherwise, <c>false</c>.
		/// </returns>
		public static bool HasAnyType(this RequestTypes requestType, RequestTypes typeset)
		{
			IEnumerable<RequestTypes> types = typeset.GetEnumerator();
			foreach (RequestTypes type in types)
			{
				if (requestType.HasType(type))
					return true;
			}
			return false;
		}
	}
}
